package org.zhaozhen.basic.service.impl;

import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.zhaozhen.basic.Constant.LoginConstant;
import org.zhaozhen.basic.businessexception.BusinessException;
import org.zhaozhen.basic.dto.LoginDto;
import org.zhaozhen.basic.service.ILoginService;
import org.zhaozhen.basic.util.*;
import org.zhaozhen.user.domain.Logininfo;
import org.zhaozhen.user.domain.User;
import org.zhaozhen.user.domain.WxUser;
import org.zhaozhen.user.mapper.LogininfoMapper;
import org.zhaozhen.user.mapper.UserMapper;
import org.zhaozhen.user.mapper.WxUserMapper;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements ILoginService{
    @Autowired
    private LogininfoMapper logininfoMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private WxUserMapper wxUserMapper;
    @Autowired
    private UserMapper userMapper;

    @Override
    public Map<String, Object> account(LoginDto dto) {
        //判断参数不为空
        if (StringUtils.isEmpty(dto.getUsername())
                || StringUtils.isEmpty(dto.getPassword())
                || StringUtils.isEmpty(dto.getType())) {
            throw new BusinessException("必要信息不能为空！！！！");
        }
        //二：根据username + type 查询logininfo 用户是否存在
        Logininfo logininfo = logininfoMapper.loadByDto(dto);


        //1.不存在 报错
        if (logininfo == null) {
            throw new BusinessException("用户名或密码错误!");
        }
        //如果存在就判断密码是否正确
        //先获取用户的盐值
        String salt = logininfo.getSalt();
        //对传进来的密码进行加密
        String newPassWord = MD5Utils.encrypByMd5(dto.getPassword() + salt);
        if (!logininfo.getPassword().equals(newPassWord)){
            throw new BusinessException("用户名或密码错误!");
        }
        //否则登陆成功
        //生成token，保存Redis
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(token, logininfo, 30, TimeUnit.MINUTES);

        //创建map对象，将数据存到map'，返回给前端
        Map<String,Object> map = new HashMap<>();
        map.put("token",token);
        //将敏感信息质控，不能返回给前端
        logininfo.setSalt(null);
        logininfo.setPassword(null);
        map.put("logininfo",logininfo);//前端登录成功，跳转到首页，直接显示登陆人
        return map;
    }

    @Override
    public AjaxResult wechat(Map<String, String> parm) {
        //获取code
        String code = parm.get("code");
        //校验code是否为空
        if (StringUtils.isEmpty(code)){
            throw new BusinessException("必要参数不能为空，可能是code为空了!");
        }
        //为链接赋值
            String getTokenLink = LoginConstant.WXUSER_GET_TOKEN_URL
                .replace("APPID", LoginConstant.APPID)
                .replace("SECRET", LoginConstant.SECRET)
                .replace("CODE", code);
        //向微信发送请求，获取token对象
        //返回的是json字符串
        String tokenJson = HttpClientUtils.httpGet(getTokenLink);
        //用阿里爹爹提供的方法将字符串转为对象
        JSONObject jsonObject = JSONObject.parseObject(tokenJson);
        String access_token = jsonObject.getString("access_token");
        String openid = jsonObject.getString("openid");
        //验证用户是否已经在我们平台扫过码了
        WxUser wxUser = wxUserMapper.loadByOpenId(openid);
        if (wxUser!=null && wxUser.getUser_id()!=null){
            //说明用户已经不是第一次扫码，直接免密登录
            Logininfo logininfo = logininfoMapper.loadByUserId(wxUser.getUser_id());
            String token = UUID.randomUUID().toString();//注意一定要toString
            redisTemplate.opsForValue().set(
                    token,
                    logininfo,//登录成功的人
                    30,
                    TimeUnit.MINUTES //分钟
            );
            // 3.2 返回前端数据 token随机串  + logininfo
            Map<String,Object> map = new HashMap<>();
            map.put("token",token);
            logininfo.setSalt(null);
            logininfo.setPassword(null);
            map.put("logininfo",logininfo);//前端登录成功，跳转到首页，直接显示登陆人
            return AjaxResult.me().setResultObj(map);
        }else {
            //用户是首次扫码，就提醒前端跳转到绑定页面
            String binder= "accessToken="+access_token+"&openid="+openid;
            return AjaxResult.me().setSuccess(false).setResultObj(binder);
        }
    }

    @Override
    public Map<String, Object> binder(Map<String, String> param) {
        //拿到map中的数据
        String phone = param.get("phone");
        String verifyCode = param.get("verifyCode");
        String accessToken = param.get("accessToken");
        String openId = param.get("openId");
        //参数空校验
        if(!StringUtils.hasLength(phone)
                ||!StringUtils.hasLength(verifyCode)
                ||!StringUtils.hasLength(accessToken)
                ||!StringUtils.hasLength(openId)){
            throw  new BusinessException("参数有问题!!!");
        }
        //看验证码是否过期
        Object oldCode = redisTemplate.opsForValue().get(LoginConstant.PHONE_BINDER + phone);
        //没有拿到验证码
        if(oldCode == null){
            throw new BusinessException("验证码已失效,请重新获取!!");
        }
        //拿到了，校验验证码是否一致
        String oldVerify = oldCode.toString().split(":")[0];
        if(!verifyCode.equalsIgnoreCase(oldVerify)){
            throw new BusinessException("验证码输入错误!!!");
        }
        //校验手机号是否被注册
        User user = userMapper.loadByPhone(phone);
        Logininfo logininfo =null;
        if (user!=null){
            logininfo = logininfoMapper.loadById(user.getLogininfo_id());
        }else {
            user = initUser(phone);
            logininfo = user2Logininfo(user);
            logininfoMapper.save(logininfo);
            user.setLogininfo_id(logininfo.getId());
            userMapper.save(user);
        }
        //根据token + openId 查询wxuser信息 设置userId并 t_wxuser
        String getWxUseUrl = LoginConstant.WXUSER_GET_URL
                .replace("ACCESS_TOKEN",accessToken)
                .replace("OPENID",openId);
        String wxUserStr = HttpClientUtils.httpGet(getWxUseUrl);
        WxUser wxUser = JSONObject.parseObject(wxUserStr, WxUser.class);
        wxUser.setUser_id(user.getId());//绑定userId
        wxUserMapper.save(wxUser);
        //免密登录
        String token = UUID.randomUUID().toString();//注意一定要toString
        redisTemplate.opsForValue().set(
                token,
                logininfo,//登录成功的人
                30,
                TimeUnit.MINUTES //分钟
        );
        // 3.2 返回前端数据 token随机串  + logininfo
        Map<String,Object> map = new HashMap<>();
        map.put("token",token);
        //我们培养的是高级技师 需要把敏感信息置空
        logininfo.setSalt(null);
        logininfo.setPassword(null);
        map.put("logininfo",logininfo);//前端登录成功，跳转到首页，直接显示登陆人
        return map;
    }

    private Logininfo user2Logininfo(User user) {
        Logininfo logininfo = new Logininfo();
        BeanUtils.copyProperties(user,logininfo);
        logininfo.setType(1);//注意
        return logininfo;
    }

    private User initUser(String phone) {
        //准备放回对象
        User user = new User();
        //设置值
        user.setUsername(phone);
        user.setPhone(phone);
        //生成盐值
        String salt = StrUtils.getComplexRandomString(32);
        //通过盐值加密密码  这里我们需要发短信告诉他默认密码
        String md5Password = MD5Utils.encrypByMd5("1" + salt);
        user.setSalt(salt);//保存盐值
        user.setPassword(md5Password);//加密之后的密码
        //返回这个对象
        return user;
    }
}
